import logging
import os
import re
import sys
import traceback
from logging.handlers import RotatingFileHandler

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QLabel, QLineEdit, QTextEdit,
    QPushButton, QSpinBox, QFileDialog, QMessageBox, QProgressBar
)
from openai import OpenAI  # 请确保 openai 库和 deepseek API 配置正确

# 日志配置：使用日志轮转，限制每个文件1MB，最多保留3个备份
log_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
log_handler = RotatingFileHandler('article_generator.log', maxBytes=1 * 1024 * 1024, backupCount=3)
log_handler.setFormatter(log_formatter)
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logger.addHandler(log_handler)

# 从环境变量中外置配置
API_KEY = os.getenv("DEEPSEEK_API_KEY")
if not API_KEY:
    # 因为这是必需的，不妨直接退出程序
    print("未找到 API 密钥，请设置环境变量 DEEPSEEK_API_KEY!")
    sys.exit(1)
API_BASE_URL = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com")
MODEL_NAME = os.getenv("DEESEEK_MODEL_NAME", "deepseek-reasoner")


def sanitize_filename(filename: str) -> str:
    """
    清洗文件名中的非法字符，让它可以在各种系统中保存。
    """
    # 替换掉常见非法字符，如 \ / : * ? " < > |
    return re.sub(r'[\\/:*?"<>|]', '_', filename)


class ArticleWorker(QThread):
    # 信号反馈进度、完成和错误信息
    progress_signal = pyqtSignal(str)
    finished_signal = pyqtSignal(str)
    error_signal = pyqtSignal(str)

    def __init__(self, prompt, api_client, parent=None):
        super().__init__(parent)
        self.prompt = prompt
        self.api_client = api_client

    def run(self):
        messages = [{"role": "user", "content": self.prompt}]
        full_response = ""
        try:
            logger.info("开始生成文章")
            response = self.api_client.chat.completions.create(
                model=MODEL_NAME,
                messages=messages,
                stream=True  # 启用流式输出
            )
            # 流式处理响应，边接收边输出
            for chunk in response:
                # 这里做个简单检查，确保 chunk 内数据存在
                if hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content:
                    content_part = chunk.choices[0].delta.content
                    full_response += content_part
                    # 可以添加简单节流逻辑，如每隔一定字符再 emit
                    self.progress_signal.emit(content_part)
            self.finished_signal.emit(full_response)
            logger.info("文章生成完成")
        except Exception as e:
            error_message = f"生成文章时出错: {str(e)}\n{traceback.format_exc()}"
            logger.error(error_message)
            self.error_signal.emit(error_message)


class ArticleGeneratorApp(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("文章生成器")
        self.setGeometry(200, 200, 600, 400)
        self.initUI()

        # API 客户端初始化
        self.client = OpenAI(api_key=API_KEY, base_url=API_BASE_URL)
        self.article_worker = None
        self.generation_in_progress = False  # 防止重复启动任务

    def initUI(self):
        layout = QVBoxLayout()

        # 文章标题输入
        self.title_label = QLabel("文章标题：")
        self.title_input = QLineEdit(self)
        layout.addWidget(self.title_label)
        layout.addWidget(self.title_input)

        # 文章主要内容输入
        self.content_label = QLabel("文章主要内容：")
        self.content_input = QTextEdit(self)
        layout.addWidget(self.content_label)
        layout.addWidget(self.content_input)

        # 文章格式输入
        self.format_label = QLabel("文章格式（如：总分总，总分等）：")
        self.format_input = QLineEdit(self)
        layout.addWidget(self.format_label)
        layout.addWidget(self.format_input)

        # 文笔风格输入
        self.style_label = QLabel("文笔风格（如：小红书风格，政府工作报告等）：")
        self.style_input = QLineEdit(self)
        layout.addWidget(self.style_label)
        layout.addWidget(self.style_input)

        # 文章大致字数
        self.word_count_label = QLabel("大致字数：")
        self.word_count_input = QSpinBox(self)
        self.word_count_input.setRange(100, 5000)
        layout.addWidget(self.word_count_label)
        layout.addWidget(self.word_count_input)

        # 生成按钮
        self.generate_button = QPushButton("生成文章", self)
        self.generate_button.clicked.connect(self.start_article_generation)
        layout.addWidget(self.generate_button)

        # 进度条：初始设为不可见
        self.progress_bar = QProgressBar(self)
        self.progress_bar.setRange(0, 0)  # 不确定进度时显示忙碌状态
        self.progress_bar.setVisible(False)
        layout.addWidget(self.progress_bar)

        # 输出框，显示生成文章内容
        self.output_text = QTextEdit(self)
        self.output_text.setReadOnly(True)
        layout.addWidget(self.output_text)

        self.setLayout(layout)

    def start_article_generation(self):
        if self.generation_in_progress:
            QMessageBox.information(self, "提示", "文章生成正在进行中，请稍候...")
            return

        title = self.title_input.text().strip()
        main_content = self.content_input.toPlainText().strip()
        format_type = self.format_input.text().strip()
        style = self.style_input.text().strip()
        word_count = self.word_count_input.value()

        # 简单输入校验
        if not title:
            QMessageBox.warning(self, "警告", "请填写文章标题！")
            return

        prompt = (
            f"请严格按照以下要求生成一篇文章：\n标题：{title}\n主要内容：{main_content}\n"
            f"格式：{format_type}\n风格：{style}\n字数：{word_count}\n"
            "在适当位置插入图片，使用格式：<图片类型，图片内容>进行标记。"
        )

        self.output_text.clear()
        self.progress_bar.setVisible(True)
        self.generate_button.setEnabled(False)
        self.generation_in_progress = True

        # 启动后台线程生成文章
        self.article_worker = ArticleWorker(prompt, self.client)
        self.article_worker.progress_signal.connect(self.append_output)
        self.article_worker.finished_signal.connect(self.on_generation_finished)
        self.article_worker.error_signal.connect(self.on_generation_error)
        self.article_worker.start()

    def append_output(self, text):
        # 自动移动光标到末尾，保证最新内容可见
        cursor = self.output_text.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.output_text.setTextCursor(cursor)
        self.output_text.ensureCursorVisible()

    def on_generation_finished(self, full_response):
        self.progress_bar.setVisible(False)
        self.generate_button.setEnabled(True)
        self.generation_in_progress = False
        # 文章生成完成后自动保存，提示用户选择保存位置和文件名
        self.save_article_to_file(self.title_input.text().strip(), full_response)

    def on_generation_error(self, error_message):
        self.progress_bar.setVisible(False)
        self.generate_button.setEnabled(True)
        self.generation_in_progress = False
        QMessageBox.critical(self, "错误", f"生成文章失败：\n{error_message}")

    def save_article_to_file(self, title, article_content):
        # 对标题进行清洗，避免文件名非法
        safe_title = sanitize_filename(title)
        default_filename = f"{safe_title}.md"
        options = QFileDialog.Options()
        file_name, _ = QFileDialog.getSaveFileName(
            self, "保存文章", default_filename,
            "Markdown Files (*.md);;All Files (*)", options=options
        )
        if file_name:
            try:
                with open(file_name, "w", encoding="utf-8") as f:
                    f.write(article_content)
                QMessageBox.information(self, "成功", f"文章已保存为 {file_name}")
                logger.info(f"文章保存为 {file_name}")
            except IOError as io_err:
                error_message = f"保存文件失败（I/O 错误）：{str(io_err)}"
                QMessageBox.critical(self, "错误", error_message)
                logger.error(error_message)
            except Exception as e:
                error_message = f"保存文件失败：{str(e)}"
                QMessageBox.critical(self, "错误", error_message)
                logger.error(error_message)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ArticleGeneratorApp()
    window.show()
    sys.exit(app.exec_())
